package com.hh.workflow.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricProcessInstanceQuery;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.persistence.entity.HistoricProcessInstanceEntity;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.task.TaskDefinition;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.hh.baseframework.exception.MessageException;
import com.hh.baseframework.util.Convert;
import com.hh.baseframework.util.check.Check;
import com.hh.baseframework.util.date.DateFormat;
import com.hh.baseframework.util.dto.PageRange;
import com.hh.workflow.bean.HhWorkFlowInfo;
import com.hh.workflow.service.inf.IUserService;
import com.hh.workflow.util.Static;

@Service
public class StartService extends ActivitiService {
	@Autowired
	private WorkFlowInfoService workFlowInfoService;
	@Autowired
	private IUserService loginUserUtilService;

	@Transactional(propagation = Propagation.SUPPORTS)
	public Map<String, Object> start(String pdkey) throws MessageException {
		ProcessDefinition processDefinition = this.repositoryService
				.createProcessDefinitionQuery().processDefinitionKey(pdkey)
				.latestVersion().singleResult();
		if (processDefinition == null) {
			throw new MessageException("流程还未部署！");
		}
		ProcessDefinitionEntity def = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
				.getDeployedProcessDefinition(processDefinition.getId());
		List<ActivityImpl> activityImpls = def.getActivities();

		String userkey = "assignee";
		for (ActivityImpl activityImpl : activityImpls) {
			if ("startEvent".equals(activityImpl.getProperty("type"))) {
				List<PvmTransition> pvmTransitionList = activityImpl
						.getOutgoingTransitions();
				userkey = "candidateUsers_"
						+ pvmTransitionList.get(0).getDestination().getId();
				break;
			}
		}
		String userid = loginUserUtilService.findLoginUserId();
		this.identityService.setAuthenticatedUserId(loginUserUtilService
				.findLoginUserId());
		Map<String, Object> paramMap = new HashMap<String, Object>();
		paramMap.put(userkey, userid);
		String objectId = UUID.randomUUID().toString();
		ProcessInstance processInstance = this.runtimeService
				.startProcessInstanceByKey(processDefinition.getKey(),
						objectId, paramMap);
		List<Task> tasks = this.taskService.createTaskQuery()
				.processInstanceId(processInstance.getId()).list();
		this.taskService.claim(tasks.get(0).getId(), userid);
		Map<String, Map<String, Object>> cellMaps = workFlowInfoService
				.findCellObjectListById(pdkey);
		Map<String, Object> activityMap = cellMaps.get(tasks.get(0)
				.getTaskDefinitionKey());
		Map<String, Object> workflowMap = cellMaps.get(Static.WORKFLOW_MAP_KEY);
		workFlowInfoService.copyWfToAct(activityMap, workflowMap);
		activityMap.put("objectId", objectId);
		activityMap.put("taskId", tasks.get(0).getId());
		activityMap.put("piid", processInstance.getId());
		activityMap.put("pdid", processInstance.getProcessDefinitionId());
		activityMap.put("activityId", tasks.get(0).getTaskDefinitionKey());
		activityMap.put("pdName", processDefinition.getName());
		activityMap.put("name", tasks.get(0).getName());
		return activityMap;
	}

	public Map<? extends String, ? extends Object> queryPagingData(
			PageRange pageRange, String pdkey) {
		HistoricProcessInstanceQuery historicProcessInstanceQuery = this.historyService
				.createHistoricProcessInstanceQuery();
		HistoricProcessInstanceQuery historicProcessInstanceQueryCount = this.historyService
				.createHistoricProcessInstanceQuery();

		if (Check.isNoEmpty(pdkey)) {
			historicProcessInstanceQuery.processDefinitionKey(pdkey);
			historicProcessInstanceQueryCount.processDefinitionKey(pdkey);
		}
		List<HistoricProcessInstance> processInstances = historicProcessInstanceQuery
				.startedBy(loginUserUtilService.findLoginUserId())
				.orderByProcessInstanceStartTime().desc()
				.listPage(pageRange.getStart(), pageRange.getEnd());
		List<Map<String, Object>> resultMaps = new ArrayList<Map<String, Object>>();
		for (HistoricProcessInstance historicProcessInstance : processInstances) {
			HistoricProcessInstanceEntity historicProcessInstanceEntity = (HistoricProcessInstanceEntity) historicProcessInstance;
			Map<String, Object> objectMap = Convert
					.objectToMapAll(historicProcessInstanceEntity);

			ProcessDefinition processDefinition = this.repositoryService
					.createProcessDefinitionQuery()
					.processDefinitionId(
							historicProcessInstance.getProcessDefinitionId())
					.singleResult();
			objectMap.put("pdName", processDefinition.getName());
			Long dur = historicProcessInstance.getDurationInMillis();
			if (historicProcessInstance.getDurationInMillis() == null) {
				dur = System.currentTimeMillis()
						- historicProcessInstance.getStartTime().getTime();
			}
			objectMap.put("durationInMillis",
					DateFormat.millisecondTOHHMMSS(dur));
			objectMap.put("pdid", processDefinition.getId());
			objectMap.put("deploymentId", processDefinition.getDeploymentId());
			resultMaps.add(objectMap);
		}

		Long count = historicProcessInstanceQueryCount.startedBy(
				loginUserUtilService.findLoginUserId()).count();
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("items", resultMaps);
		map.put("total", count);
		return map;
	}

	public HhWorkFlowInfo findWorkFlowByDataId(String dataId) {
		HhWorkFlowInfo workFlowInfo = workFlowInfoService
				.findObjectByDataId(dataId);
		return workFlowInfo;
	}

	public void deleteByIds(String ids) {
		List<String> piidList = Convert.strToList(ids);
		for (String piid : piidList) {
			List<ProcessInstance> processInstanceList = runtimeService
					.createProcessInstanceQuery().processInstanceId(piid)
					.list();
			if (processInstanceList == null ? false : processInstanceList
					.size() == 0 ? false : true) {
				runtimeService.deleteProcessInstance(piid, null);
			}
			this.historyService.deleteHistoricProcessInstance(piid);
		}

	}

	public void end(String ids) {
		List<String> piidList = Convert.strToList(ids);
		for (String piid : piidList) {
			runtimeService.deleteProcessInstance(piid,
					loginUserUtilService.findLoginUserId());
		}
	}
}
